﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;

namespace APP.Win32
{
    public enum KeyboardLayoutEnum
    {
        Unchanged,  // 不变
        EN_US,  //00000409英语美式键盘
        EN_GB,  //00000809英语英式键盘
        //ZH_CN,  //00000804中文简体
    }

    public class UILangEnvironment
    {
        [DllImport("kernel32.dll")]
        private static extern UInt16 GetUserDefaultUILanguage();

        [DllImport("kernel32.dll")]
        private static extern UInt16 GetSystemDefaultLangID();

        [DllImport("kernel32.dll")]
        private static extern UInt16 GetUserDefaultLangID();

        /// <summary>
        /// 用户缺省界面语言
        /// </summary>
        public static UInt16 UserDefaultUILanguage
        {
            get
            {
                return GetUserDefaultUILanguage();
            }
        }

        /// <summary>
        /// 用户缺省语言
        /// </summary>
        public static UInt16 UserDefaultLangID
        {
            get
            {
                return GetUserDefaultLangID();
            }
        }

        /// <summary>
        /// 系统缺省语言
        /// </summary>
        public static UInt16 SystemDefaultLangID
        {
            get
            {
                return GetSystemDefaultLangID();
            }
        }
    }

    public enum SystemMetric
    {
        /// <summary>
        /// Nonzero if the meanings of the left and right mouse buttons are swapped; otherwise, 0.
        /// </summary>
        SM_CXSCREEN = 0,// '屏幕宽度
        SM_CYSCREEN = 1, //'屏幕高度
        SM_SWAPBUTTON = 23,
        SM_XVIRTUALSCREEN = 76,
        SM_YVIRTUALSCREEN = 77,
        SM_CXVIRTUALSCREEN = 78,
        SM_CYVIRTUALSCREEN = 79
    }

    public static class NativeMethods
    {

        public const UInt32 SWP_NOSIZE = 0x0001;//保留当前大小（忽略cx和cy参数）。
        public const UInt32 SWP_NOMOVE = 0x0002;//保留当前位置（忽略X和Y参数）。
        public const UInt32 SWP_NOZORDER = 0x0004;//保留当前的Z顺序（忽略hWndInsertAfter参数）。
        public const UInt32 SWP_NOREDRAW = 0x0008;//不重绘更改。
        public const int SWP_NOACTIVATE = 0x0010;//不激活窗口。

        public const UInt32 SWP_FRAMECHANGED = 0x0020; /* The frame changed: send WM_NCCALCSIZE */
        public const UInt32 SWP_SHOWWINDOW = 0x0040;
        public const UInt32 SWP_HIDEWINDOW = 0x0080;
        public const UInt32 SWP_NOCOPYBITS = 0x0100;
        public const UInt32 SWP_NOOWNERZORDER = 0x0200; /* Don’t do owner Z ordering */
        public const UInt32 SWP_NOSENDCHANGING = 0x0400; /* Don’t send WM_WINDOWPOSCHANGING */
        public const UInt32 TOPMOST_FLAGS =
            SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOSENDCHANGING;

        public const UInt32 WINDOW_CAN_MOVE_RESIZE =
            SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSENDCHANGING;//可以改变大小和位置
        public const UInt32 WINDOW_JUST_MOVE = WINDOW_CAN_MOVE_RESIZE | SWP_NOSIZE; //仅移动窗口
        public const UInt32 WINDOW_JUST_RESIZE = WINDOW_CAN_MOVE_RESIZE | SWP_NOMOVE;//仅改变大小

        public const int WS_EX_TOOLWINDOW = 0x00000080;
        public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);//将窗口放在所有非最顶层的窗口上方。即使停用窗口，窗口也会保持最高位置。
        public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); //将窗口放在所有非最顶层窗口（即所有最顶层窗口后面）上方。如果窗口已经是非最顶层窗口，则此标志无效。
        public static readonly IntPtr HWND_TOP = new IntPtr(0);//将窗口置于Z顺序的顶部。
        public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);//将窗口放在Z顺序的底部。如果hWnd参数标识最顶层窗口，则窗口将失去其最顶层状态，并放置在所有其他窗口的底部。

        // MSHTML
        public const int SMTO_ABORTIFHUNG = 2;
        public static readonly int WM_HTML_GETOBJECT = RegisterWindowMessage("WM_HTML_GETOBJECT");
        public static readonly Guid IID_IHTMLDocument = new Guid("626fc520-a41e-11cf-a731-00a0c9082637");

        public const int WM_HOTKEY = 0x0312;
        public const int HOTKEYID = 0x9999;

        /*---------ShowWindwo 控制窗口状态--------------*/
        //public const int SW_FORCEMINIMIZE = 11;//最小化窗口,即使拥有窗口的线程没有响应。这个标志最小化窗口时只能使用一个不同的线程。
        public const int SW_HIDE = 0;//隐藏窗口和激活另一个窗口。
        public const int SW_MAXIMIZE = 3;//最大化指定的窗口。
        public const int SW_MINIMIZE = 6;//最小化指定的窗口和激活下一个顶级窗口在Z顺序
        public const int SW_RESTORE = 9;//激活并显示窗口。如果窗口最小化或最大化,系统恢复原来的大小和位置。应用程序应该指定这个标志时恢复最小化窗口。
        public const int SW_SHOW = 5;//激活窗口,显示当前的大小和位置。
        //public const int SW_SHOWDEFAULT = 10;//设置显示状态基于SW_值中指定STARTUPINFO结构传递给CreateProcess功能的程序,启动应用程序。
        public const int SW_SHOWMAXIMIZED = 3;//激活窗口并显示它作为最大化窗口。
        public const int SW_SHOWMINIMIZED = 2;//激活窗口并显示最小化窗口。
        //public const int SW_SHOWMINNOACTIVE = 7;//显示窗口最小化窗口。这个值SW_SHOWMINIMIZED相似,除了不激活的窗口。
        public const int SW_SHOWNA = 8;//显示当前窗口的大小和位置。这个值SW_SHOW相似,除了不激活的窗口。
        //public const int SW_SHOWNOACTIVATE = 4;//将显示一个窗口在其最近的大小和位置。这个值SW_SHOWNORMAL相似,除了不激活的窗口。
        public const int SW_SHOWNORMAL = 1;//激活并显示一个窗口。如果窗口最小化或最大化,系统恢复原来的大小和位置。应用程序应该指定这个标志第一次时显示窗口。
        /*---------ShowWindwo 控制窗口状态--------------*/

        /*---------GetWindowLong 检索有关指定窗口的信息--------------*/
        public const int GWL_EXSTYLE = -20;//检索扩展窗口样式。
        public const int GWL_HINSTANCE = -6;//检索应用程序实例的句柄。
        public const int GWL_HWNDPARENT = -8;//检索父窗口的句柄（如果有）。
        public const int GWL_ID = -12;//检索窗口的标识符。
        public const int GWL_STYLE = -16;//检索窗口样式。
        public const int GWL_USERDATA = -21;//检索与窗口关联的用户数据。此数据旨在供创建窗口的应用程序使用。它的值最初为零。
        public const int GWL_WNDPROC = -4;//检索窗口过程的地址，或表示窗口过程地址的句柄。您必须使用CallWindowProc函数来调用窗口过程。
        /*---------GetWindowLong 检索有关指定窗口的信息--------------*/
        //详见 https://docs.microsoft.com/zh-cn/windows/desktop/winmsg/window-styles
        public const long WS_VISIBLE = 0x10000000L;//窗口最初是可见的。
        public const long WS_ICONIC = 0x20000000L;//窗口最初被最小化。与WS_MINIMIZE样式相同。
        public const long WS_MINIMIZE = 0x20000000L;//窗口最初被最小化。与WS_ICONIC风格相同。
        public const long WS_MAXIMIZE = 0x01000000L;//窗口最初是最大化的。

        /// <summary>
        /// 状态结果
        /// </summary>
        public struct GetWindowLong_STYLE
        {
            public bool WS_VISIBLE;
            public bool WS_ICONIC;
            public bool WS_MINIMIZE;
            public bool WS_MAXIMIZE;
        }
        /*---------GetWindowLong 检索有关指定窗口的信息--------------*/
        /*---------防休眠--------------*/
        private const uint ES_SYSTEM_REQUIRED = 0x00000001;
        private const uint ES_DISPLAY_REQUIRED = 0x00000002;
        private const uint ES_CONTINUOUS = 0x80000000;
        //定义API函数
        [DllImport("kernel32.dll")]
        static extern uint SetThreadExecutionState(uint esFlags);
        /*---------防休眠--------------*/

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern int GetSystemMetrics(SystemMetric nIndex);

        [DllImport("wininet.dll")]
        public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);


        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);

        // Pinvoke
        public delegate bool ConsoleEventDelegate(int eventType);

        // Keeps it from getting garbage collected
        public static ConsoleEventDelegate Handler;

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();

        /// <summary>
        /// 设置窗口  参考链接 https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowpos
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hwndAfter, int x, int y, int width, int height, int flags);
        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
        /// <summary>
        /// https://docs.microsoft.com/zh-cn/windows/desktop/api/winuser/nf-winuser-setforegroundwindow
        /// <para>将创建指定窗口的线程置于前台并激活窗口。键盘输入被定向到窗口，并且为用户改变各种视觉提示。系统为创建前台窗口的线程分配的优先级略高于其他线程的优先级。</para>
        /// </summary>
        /// <param name="hWnd"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        [DllImport("user32.dll")]
        public static extern long GetWindowLongA(IntPtr hWnd, int nIndex);
        [DllImport("user32.dll")]
        public static extern bool IsIconic(IntPtr hWnd);
        [DllImport("user32.dll")]
        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        [DllImport("user32", EntryPoint = "RegisterWindowMessage")]
        public static extern int RegisterWindowMessage(string lpString);

        [DllImport("user32.dll")]
        public static extern bool SetProcessDPIAware();

        [DllImport("user32.dll", EntryPoint = "SendMessageTimeoutA", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SendMessageTimeout(
            [In] IntPtr MSG,
            [In] int hWnd,
            [In] int wParam,
            [In] int lParam,
            [In] int fuFlags,
            [In] int uTimeout,
            [In, Out] ref int lpdwResult
        );

        [DllImport("oleacc.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ObjectFromLresult(
            [In] int lResult,
            [In] ref Guid riid,
            [In] int wParam,
            [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppvObject
        );
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);
        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(ref Point lpPoint);

        public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int processId);

        [DllImport("User32.dll")]
        public static extern bool RegisterHotKey(IntPtr hWnd, Int32 id, uint fsModifiers, uint vk);

        [DllImport("User32.dll")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        [DllImport("user32.dll", ExactSpelling = true)]
        public static extern IntPtr GetAncestor(IntPtr hwnd, uint flags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWindow(IntPtr hWnd);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int GetWindowModuleFileName(IntPtr hWnd, StringBuilder lpFilename, int nSize);

        [DllImport("user32.dll")]
        public static extern int MessageBoxTimeoutA(IntPtr hWnd, string msg, string Caption, int type, int DWORD, int time);

        /// <summary>
        /// Get executable file name from window handle
        /// </summary>
        /// <param name="hwnd"></param>
        /// <returns></returns>
        public static string GetModuleName(IntPtr hwnd)
        {
            var builder = new StringBuilder(1024);
            var len = GetWindowModuleFileName(hwnd, builder, builder.Capacity);

            return builder.ToString();
        }

        /// <summary>
        /// 移动窗体
        /// </summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint);


        #region Set System Mouse Cursor

        public enum SYSTEM_CURSORS : int
        {
            /// <summary>
            /// Standard arrow and small hourglass
            /// </summary>
            APPSTARTING = 32650,
            /// <summary>
            /// Standard arrow
            /// </summary>
            NORMAL = 32512,
            /// <summary>
            /// Crosshair
            /// </summary>
            CROSS = 32515,
            /// <summary>
            /// Windows 2000/XP: Hand
            /// </summary>
            HAND = 32649,
            /// <summary>
            /// Arrow and question mark
            /// </summary>
            HELP = 32651,
            /// <summary>
            /// I-beam
            /// </summary>
            IBEAM = 32513,
            /// <summary>
            /// Slashed circle
            /// </summary>
            NO = 32648,
            /// <summary>
            /// Four-pointed arrow pointing north, south, east, and west
            /// </summary>
            SIZEALL = 32646,
            /// <summary>
            /// Double-pointed arrow pointing northeast and southwest
            /// </summary>
            SIZENESW = 32643,
            /// <summary>
            /// Double-pointed arrow pointing north and south
            /// </summary>
            SIZENS = 32645,
            /// <summary>
            /// Double-pointed arrow pointing northwest and southeast
            /// </summary>
            SIZENWSE = 32642,
            /// <summary>
            /// Double-pointed arrow pointing west and east
            /// </summary>
            SIZEWE = 32644,
            /// <summary>
            /// Vertical arrow
            /// </summary>
            UP = 32516,
            /// <summary>
            /// Hourglass
            /// </summary>
            WAIT = 32514
        }

        public const uint SPI_SETCURSORS = 87;
        public const uint SPIF_SENDWININICHANGE = 2;
        [DllImport("user32")]
        private static extern IntPtr LoadCursorFromFile(string fileName);

        [DllImport("User32.DLL")]
        public static extern bool SetSystemCursor(IntPtr hcur, uint id);

        [DllImport("user32.dll")]
        public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);

        [DllImport("user32.dll")]
        public static extern IntPtr CopyIcon(IntPtr pcur);

        #endregion


        #region Set Topmost property
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        public delegate bool CallBackPtr(IntPtr hwnd, int lParam);

        [DllImport("user32.dll")]
        public static extern int EnumWindows(CallBackPtr callPtr, int lPar);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        // 外面不要直接调用GetWindowText，获取本进程的窗口名的时候，可能会发生卡死。请调用: GetWindowTextSkipCurrentProcess
        // 参考: https://www.cnblogs.com/xylc/p/3552467.html
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr WindowFromPoint(Point point);

        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);

        [DllImport("user32")]
        public static extern IntPtr GetDesktopWindow();

        private const string dummy_current_iBot_processName = "DummyIbotWinName";
        private static int current_process_id = 0;
        public static int GetCurrentProcessId()
        {
            if (0 == current_process_id)
            {
                current_process_id = Process.GetCurrentProcess().Id;
            }
            return current_process_id;
        }

        public static bool IsCurrentProcessHWnd(IntPtr hWnd)
        {
            int hwndProcessId;
            GetWindowThreadProcessId(hWnd, out hwndProcessId);
            bool isCurrent = GetCurrentProcessId() == hwndProcessId;
            return isCurrent;
        }

        public static int GetWindowTextSkipCurrentProcess(IntPtr hWnd, StringBuilder lpString, int nMaxCount, out bool isCurrentProcessWnd)
        {
            int length;
            isCurrentProcessWnd = IsCurrentProcessHWnd(hWnd);
            if (isCurrentProcessWnd)
            {
                lpString.Append(dummy_current_iBot_processName);
                length = dummy_current_iBot_processName.Length;
            }
            else
            {
                length = GetWindowText(hWnd, lpString, nMaxCount);
            }
            return length;
        }

        public static string ConvertPtrToString(IntPtr intV, bool isHex)
        {
            string str = isHex ? $"{((Int64)intV):X}" : $"{((Int64)intV)}";
            return str;
        }

        public static IntPtr ConvertStringToPtr(string str, bool isHex)
        {
            System.Globalization.NumberStyles numStyle = isHex ? System.Globalization.NumberStyles.HexNumber : System.Globalization.NumberStyles.Integer;
            IntPtr intV = new IntPtr(Int64.Parse(str, numStyle));
            return intV;
        }

        public static Rectangle getDesktopRect()
        {
            try
            {
                RECT rect = new RECT();
                IntPtr hDesktopWin = GetDesktopWindow();
                bool result = GetWindowRect(hDesktopWin, out rect);
                if (!result)
                {
                    return Rectangle.Empty;
                }

                return Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);
            }
            catch (Exception ex)
            {
                return Rectangle.Empty;
            }
        }

        /// <summary>
        /// Callback method to be used when enumerating windows.
        /// </summary>
        /// <param name="handle">Handle of the next window</param>
        /// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
        /// <returns>True to continue the enumeration, false to bail</returns>
        private static bool EnumWindow(IntPtr handle, IntPtr pointer)
        {
            GCHandle gch = GCHandle.FromIntPtr(pointer);
            List<IntPtr> list = gch.Target as List<IntPtr>;
            if (list == null)
            {
                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
            }
            list.Add(handle);
            //  You can modify this to check to see if you want to cancel the operation, then return a null here
            return true;
        }

        /// <summary>
        /// Delegate for the EnumChildWindows method
        /// </summary>
        /// <param name="hWnd">Window handle</param>
        /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
        /// <returns>True to continue enumerating, false to bail.</returns>
        public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        /// <summary>
        /// Returns a list of child windows
        /// </summary>
        /// <param name="parent">Parent of the windows to return</param>
        /// <returns>List of child windows</returns>
        public static List<IntPtr> GetChildWindows(IntPtr parent)
        {
            List<IntPtr> result = new List<IntPtr>();
            GCHandle listHandle = GCHandle.Alloc(result);
            try
            {
                EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
            }
            finally
            {
                if (listHandle.IsAllocated)
                    listHandle.Free();
            }
            return result;
        }
        #endregion

        #region User32 Helper
        public static void SetSystemCursor(SYSTEM_CURSORS cursor)
        {
            SetSystemCursor(CopyIcon(LoadCursor(IntPtr.Zero, (int)cursor)), (int)SYSTEM_CURSORS.NORMAL);
        }

        public static void RestoreSystemCursor()
        {
            SystemParametersInfo(SPI_SETCURSORS, 0, IntPtr.Zero, SPIF_SENDWININICHANGE);
        }

        public static string GetClassNameFromHandle(IntPtr hwnd)
        {
            StringBuilder classNameBuffer = new StringBuilder(256);
            NativeMethods.GetClassName(hwnd, classNameBuffer, classNameBuffer.Capacity);
            return classNameBuffer.ToString();
        }

        public static string GetWindowTextFromHandle(IntPtr hwnd)
        {
            bool isCurrentProcessWnd = IsCurrentProcessHWnd(hwnd);
            if (isCurrentProcessWnd) // 不支持获取当前进程的WindowText
            {
                return string.Empty;
            }

            int length = NativeMethods.GetWindowTextLength(hwnd);
            if (length == 0)
                return string.Empty;
            StringBuilder windowName = new StringBuilder(length + 1);
            int titleLength = GetWindowTextSkipCurrentProcess(hwnd, windowName, windowName.Capacity, out isCurrentProcessWnd);
            return windowName.ToString().Substring(0, titleLength);
        }
        /// <summary>
        /// 获取并解析窗体的状态
        /// </summary>
        /// <param name="winHwnd"></param>
        /// <returns></returns>
        public static GetWindowLong_STYLE GetWindowLongSTYLE(IntPtr winHwnd)
        {
            long windowLong = GetWindowLongA(winHwnd, GWL_STYLE);
            var result = WindowLongAnalysis(windowLong);
            return result;
        }

        /// <summary>
        /// 分析窗体style
        /// </summary>
        /// <param name="windowLong"></param>
        /// <returns></returns>
        public static GetWindowLong_STYLE WindowLongAnalysis(long windowLong)
        {
            GetWindowLong_STYLE result = new GetWindowLong_STYLE();
            result.WS_VISIBLE = ((windowLong & WS_VISIBLE) != 0);
            result.WS_MINIMIZE = ((windowLong & WS_MINIMIZE) != 0);
            result.WS_MAXIMIZE = ((windowLong & WS_MAXIMIZE) != 0);
            return result;
        }
        #endregion

        /// <summary>
        ///  防休眠
        /// </summary>
        /// <param name="allowAntiDormancy"></param>
        public static void SetAntiDormancy(bool allowAntiDormancy)
        {
            if (allowAntiDormancy)
            {
                //阻止休眠时调用
                SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED);
            }
            else
            {
                //恢复休眠时调用
                SetThreadExecutionState(ES_CONTINUOUS);
            }
        }

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);

        // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
        public const int WM_CLIPBOARDUPDATE = 0x031D;
        public static IntPtr HWND_MESSAGE = new IntPtr(-3);

        // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool AddClipboardFormatListener(IntPtr hwnd);

        // See http://msdn.microsoft.com/en-us/library/ms633541%28v=vs.85%29.aspx
        // See http://msdn.microsoft.com/en-us/library/ms649033%28VS.85%29.aspx
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        public static string GetLastWin32ErrorMessage(string functionName)
        {
            var code = Marshal.GetLastWin32Error();
            var ex = new Win32Exception(Marshal.GetLastWin32Error());
            string message = String.Format("{0} Error: {1} {2}", functionName, code, ex.Message);
            return message;
        }

        public static Win32Exception GetLastWin32Error(string functionName)
        {
            var code = Marshal.GetLastWin32Error();
            var ex = new Win32Exception(Marshal.GetLastWin32Error());
            // return new Win32Exception(Marshal.GetLastWin32Error());
            return new Win32Exception(Marshal.GetLastWin32Error(), functionName + "::" + ex.Message);
        }


        #region DPI
        [DllImport("user32.dll")]
        public static extern IntPtr GetDC(IntPtr ptr);

        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);

        [DllImport("gdi32.dll")]
        public static extern IntPtr CreateDC(
            string lpszDriver,  // driver name
            string lpszDevice,  // device name
            string lpszOutput,  // not used; should be NULL
            Int64 lpInitData    // optional printer data
        );

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceCaps(
            IntPtr hdc,         // handle to DC
            int nIndex          // index of capability
        );
        #endregion

        #region 进程/线程相关

        /*-----------线程挂起、线程恢复-----------*/
        public const int TERMINATE = 0x0001;
        public const int SUSPEND_RESUME = 0x0002;
        public const int GET_CONTEXT = 0x0008;
        public const int SET_CONTEXT = 0x0010;
        public const int SET_INFORMATION = 0x0020;
        public const int QUERY_INFORMATION = 0x0040;
        public const int SET_THREAD_TOKEN = 0x0080;
        public const int IMPERSONATE = 0x0100;
        public const int DIRECT_IMPERSONATION = 0x0200;

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenThread(int dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

        [DllImport("kernel32.dll")]
        public static extern uint SuspendThread(IntPtr hThread);

        [DllImport("kernel32.dll")]
        public static extern uint ResumeThread(IntPtr hThread);

        #endregion

        //————————————————
        //版权声明：本文为CSDN博主「config_man」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
        //原文链接：https://blog.csdn.net/config_man/article/details/78445336
        [DllImport("user32.dll")]
        private static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lparam);

        [DllImport("user32.dll")]
        private static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);

        private static uint WM_INPUTLANGCHANGEREQUEST = 0x0050;
        private static int HWND_BROADCAST = 0xffff;
        private static uint KLF_ACTIVATE = 1;

        private static readonly Dictionary<KeyboardLayoutEnum, string> KEYBOARD_LAYOUT_STRINGS =
            new Dictionary<KeyboardLayoutEnum, string>() {
                { KeyboardLayoutEnum.EN_US, "00000409" }, //英语美式键盘
                { KeyboardLayoutEnum.EN_GB, "00000809" } //英语英式键盘
                // { KeyboardLayoutEnum.CN_ZH, "00000804" }, //中文简体
        };
        //调用此方法时，将屏蔽中文输入法(操作系统级别，即使使用快捷键ctrl+shift也还原不回中文输入法)
        public static void ChangeKeyboardLayout(KeyboardLayoutEnum keyboardLayout)
        {
            string layoutStr;
            switch (keyboardLayout)
            {
                case KeyboardLayoutEnum.Unchanged:
                    break;
                case KeyboardLayoutEnum.EN_GB:
                case KeyboardLayoutEnum.EN_US:
                    layoutStr = KEYBOARD_LAYOUT_STRINGS[keyboardLayout];
                    PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, LoadKeyboardLayout(layoutStr, KLF_ACTIVATE));
                    break;
                default:
                    throw new Exception("ChangeKeyboardLayout 未知的键盘布局! keyboardLayout:{keyboardLayout}");
            }
        }


        #region  文件
        // 关闭64位（文件系统）的操作转向
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
        // 开启64位（文件系统）的操作转向
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);


        // IntPtr oldWOW64State = new IntPtr();
        // Wow64DisableWow64FsRedirection(ref oldWOW64State);   // 关闭64位（文件系统）的操作转向
        // 省略相关代码（如系统目录下的文件操作）.....
        // Wow64RevertWow64FsRedirection(oldWOW64State);        // 开启64位（文件系统）的操作转向
        #endregion






    }
}
